#include "UnitGroup.h"
#include "Manager.h"
#include "ConcurrecyQueue.h"

UnitGroup::UnitGroup(int actionSize)
{
	units = Unitset();
	actionsQueue = new ConcurrencyQueue<BasicAction*, ActionCompare, ConcurrentCompare>(actionSize);
	enabled = true;
}

UnitGroup::UnitGroup(Unitset unitSet, int actionSize)
{
	units = Unitset(unitSet);
	actionsQueue = new ConcurrencyQueue<BasicAction*, ActionCompare, ConcurrentCompare>(actionSize);
	enabled = true;
}

Unitset* UnitGroup::getUnits()
{
	return &units;
}

void UnitGroup::addUnit(Unit *unit)
{
	Unitset set = Unitset();
	set.push_back(unit);
	units|=set;
}

void UnitGroup::addAction(BasicAction *newAction, BasicManager *manager, int priority, int order)
{
	BasicAction *toPush = newAction->clone();
	toPush->priority = priority;
	toPush->order = order;
	toPush->setManager(manager);
	toPush->group = this;
	actionsQueue->push(order,toPush);
	managers.insert(manager);
}

void UnitGroup::nextAction(int level)
{
	if(!actionsQueue->empty(level)) {
		BasicAction *next = actionsQueue->top(level);
		actionsQueue->pop(level);
		delete next;
	}
}

void UnitGroup::onActionCompleted(BasicAction* action)
{
	nextAction(action->getOrder());
}

void UnitGroup::onTaskCompleted()
{
	if(managers.empty())
		return;

	for(std::set<BasicManager*>::iterator i = managers.begin(); i != managers.end(); ++i) {
		BasicManager *manager = *i;
		if(manager == NULL)
			continue;

		manager->onTaskCompleted(this);
	}
	stop();
}

void UnitGroup::think()
{
	if(!enabled)
		return;

	priority_queue<BasicAction*, vector<BasicAction*>, ConcurrentCompare> actions = actionsQueue->top();
	while(!actions.empty()) {
		// Get a prioritized set of concurrent actions in the
		// proper dependency order and make them think.
		BasicAction *top = actions.top();
		if(top->isStopped()) { // Start any new Actions
			top->start();
			Broodwar->printf("Starting Action %x", top->group);
		}

		top->think();
		actions.pop();
	}
}

int UnitGroup::getCount()
{
	int size = 0;
	for(Unitset::iterator i = units.begin(); i != units.end(); ++i) {
		// Get a direct pointer to our unit so we do not have to continuously dereference the iterator
		Unit *u = *i;
		if(u == NULL || !u->exists()) // watch this area
			units.remove(i);
		else
			size++;
	}
	return size;
}

UnitGroup::~UnitGroup()
{
	delete actionsQueue;
}